home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / tvg103.zip / TVGDEMO.PAS < prev    next >
Pascal/Delphi Source File  |  1992-07-29  |  17KB  |  637 lines

  1. {************************************************}
  2. {                                                }
  3. {   Turbo Pascal 6.0                             }
  4. {   Turbo Vision Demo                            }
  5. {   Copyright (c) 1990 by Borland International  }
  6. {                                                }
  7. {************************************************}
  8.  
  9. program TVDemo;
  10.  
  11. {$X+,S-}
  12. {$M 16384,8192,655360}
  13.  
  14. { Turbo Vision demo program. This program uses many of the Turbo
  15.   Vision standard and demo units, including:
  16.  
  17.     StdDlg    - Open file browser, change directory tree.
  18.     MsgBox    - Simple dialog to display messages.
  19.     ColorSel  - Color customization.
  20.     Gadgets   - Shows system time and available heap space.
  21.     AsciiTab  - ASCII table.
  22.     Calendar  - View a month at a time
  23.     Calc      - Desktop calculator.
  24.     FViewer   - Scroll through text files.
  25.     HelpFile  - Context sensitive help.
  26.     MouseDlg  - Mouse options dialog.
  27.     Puzzle    - Simple brain puzzle.
  28.  
  29.   And of course this program includes many standard Turbo Vision
  30.   objects and behaviors (menubar, desktop, status line, dialog boxes,
  31.   mouse support, window resize/move/tile/cascade).
  32. }
  33.  
  34. uses
  35.   Dos, TvGraph, Objects, Drivers, Memory, Views, Menus, Dialogs, StdDlg, MsgBox, App,
  36.   DemoCmds, {Gadgets, }Puzzle, Calendar, AsciiTab, Calc, FViewer, HelpFile,
  37.   DemoHelp, ColorSel, MouseDlg, Styx, Crt;
  38.  
  39. type
  40.  
  41.   { TTVDemo }
  42.  
  43.   PTVDemo = ^TTVDemo;
  44.   TTVDemo = object(TApplication)
  45. {    Clock: PClockView;
  46.     Heap: PHeapView;}
  47.     constructor Init;
  48.     procedure FileOpen(WildCard: PathStr);
  49.     procedure GetEvent(var Event: TEvent); virtual;
  50.     function GetPalette: PPalette; virtual;
  51.     procedure HandleEvent(var Event: TEvent); virtual;
  52.     procedure Idle; virtual;
  53.     procedure InitMenuBar; virtual;
  54.     procedure InitStatusLine; virtual;
  55.     procedure LoadDesktop(var S: TStream);
  56.     procedure OutOfMemory; virtual;
  57.     procedure StoreDesktop(var S: TStream);
  58.     procedure ViewFile(FileName: PathStr);
  59.   end;
  60.  
  61. { CalcHelpName }
  62.  
  63. function CalcHelpName: PathStr;
  64. var
  65.   EXEName: PathStr;
  66.   Dir: DirStr;
  67.   Name: NameStr;
  68.   Ext: ExtStr;
  69. begin
  70.   if Lo(DosVersion) >= 3 then EXEName := ParamStr(0)
  71.   else EXEName := FSearch('TVDEMO.EXE', GetEnv('PATH'));
  72.   FSplit(EXEName, Dir, Name, Ext);
  73.   if Dir[Length(Dir)] = '\' then Dec(Dir[0]);
  74.   CalcHelpName := FSearch('DEMOHELP.HLP', Dir);
  75. end;
  76.  
  77.  
  78. { TTVDemo }
  79. constructor TTVDemo.Init;
  80. var
  81.   R: TRect;
  82.   I: Integer;
  83.   FileName: PathStr;
  84. begin
  85.   TApplication.Init;
  86.   ShadowSize.X:=0;
  87.   ShadowSize.Y:=0;
  88.   RegisterObjects;
  89.   RegisterViews;
  90.   RegisterMenus;
  91.   RegisterDialogs;
  92.   RegisterApp;
  93.   RegisterHelpFile;
  94.   RegisterPuzzle;
  95.   RegisterCalendar;
  96.   RegisterAsciiTab;
  97.   RegisterCalc;
  98.   RegisterFViewer;
  99.   RegisterStyx;
  100.  
  101. {  GetExtent(R);
  102.   R.A.X := R.B.X - 9; R.B.Y := R.A.Y + 1;
  103.   Clock := New(PClockView, Init(R));
  104.   Insert(Clock);
  105.  
  106.   GetExtent(R);
  107.   Dec(R.B.X);
  108.   R.A.X := R.B.X - 9; R.A.Y := R.B.Y - 1;
  109.   Heap := New(PHeapView, Init(R));
  110.   Insert(Heap); }
  111.  
  112.   for I := 1 to ParamCount do
  113.   begin
  114.     FileName := ParamStr(I);
  115.     if FileName[Length(FileName)] = '\' then
  116.       FileName := FileName + '*.*';
  117.     if (Pos('?', FileName) = 0) and (Pos('*', FileName) = 0) then
  118.       ViewFile(FExpand(FileName))
  119.     else FileOpen(FileName);
  120.   end;
  121. end;
  122.  
  123. procedure TTVDemo.FileOpen(WildCard: PathStr);
  124. var
  125.   D: PFileDialog;
  126.   FileName: PathStr;
  127. begin
  128.   D := New(PFileDialog, Init(WildCard, 'Open a File',
  129.     '~N~ame', fdOpenButton + fdHelpButton, 100));
  130.   D^.HelpCtx := hcFOFileOpenDBox;
  131.   if ValidView(D) <> nil then
  132.   begin
  133.     if Desktop^.ExecView(D) <> cmCancel then
  134.     begin
  135.       D^.GetFileName(FileName);
  136.       ViewFile(FileName);
  137.     end;
  138.     Dispose(D, Done);
  139.   end;
  140. end;
  141.  
  142. procedure TTVDemo.GetEvent(var Event: TEvent);
  143. var
  144.   W: PWindow;
  145.   HFile: PHelpFile;
  146.   HelpStrm: PDosStream;
  147. const
  148.   HelpInUse: Boolean = False;
  149. begin
  150.   TApplication.GetEvent(Event);
  151.   case Event.What of
  152.     evCommand:
  153.       if (Event.Command = cmHelp) and not HelpInUse then
  154.       begin
  155.         HelpInUse := True;
  156.         HelpStrm := New(PDosStream, Init(CalcHelpName, stOpenRead));
  157.         HFile := New(PHelpFile, Init(HelpStrm));
  158.         if HelpStrm^.Status <> stOk then
  159.         begin
  160.           MessageBox('Could not open help file.', nil, mfError + mfOkButton);
  161.           Dispose(HFile, Done);
  162.         end
  163.         else
  164.         begin
  165.           W := New(PHelpWindow,Init(HFile, GetHelpCtx));
  166.           if ValidView(W) <> nil then
  167.           begin
  168.             ExecView(W);
  169.             Dispose(W, Done);
  170.           end;
  171.           ClearEvent(Event);
  172.         end;
  173.         HelpInUse := False;
  174.       end;
  175.     evMouseDown:
  176.       if Event.Buttons <> 1 then Event.What := evNothing;
  177.   end;
  178. end;
  179.  
  180. function TTVDemo.GetPalette: PPalette;
  181. const
  182.   CNewColor = CColor + CHelpColor;
  183.   CNewBlackWhite = CBlackWhite + CHelpBlackWhite;
  184.   CNewMonochrome = CMonochrome + CHelpMonochrome;
  185.   P: array[apColor..apMonochrome] of string[Length(CNewColor)] =
  186.     (CNewColor, CNewBlackWhite, CNewMonochrome);
  187. begin
  188.   GetPalette := @P[AppPalette];
  189. end;
  190.  
  191. procedure TTVDemo.HandleEvent(var Event: TEvent);
  192.  
  193. procedure ChangeDir;
  194. var
  195.   D: PChDirDialog;
  196. begin
  197.   D := New(PChDirDialog, Init(cdNormal + cdHelpButton, 101));
  198.   D^.HelpCtx := hcFCChDirDBox;
  199.   if ValidView(D) <> nil then
  200.   begin
  201.     DeskTop^.ExecView(D);
  202.     Dispose(D, Done);
  203.   end;
  204. end;
  205.  
  206. procedure Tile;
  207. var
  208.   R: TRect;
  209. begin
  210.   Desktop^.GetExtent(R);
  211.   Desktop^.Tile(R);
  212. end;
  213.  
  214. procedure Cascade;
  215. var
  216.   R: TRect;
  217. begin
  218.   Desktop^.GetExtent(R);
  219.   Desktop^.Cascade(R);
  220. end;
  221.  
  222. procedure Puzzle;
  223. var
  224.   P: PPuzzleWindow;
  225. begin
  226.   P := New(PPuzzleWindow, Init);
  227.   P^.HelpCtx := hcPuzzle;
  228.   Desktop^.Insert(ValidView(P));
  229. end;
  230.  
  231. procedure Calendar;
  232. var
  233.   P: PCalendarWindow;
  234. begin
  235.   P := New(PCalendarWindow, Init);
  236.   P^.HelpCtx := hcCalendar;
  237.   Desktop^.Insert(ValidView(P));
  238. end;
  239.  
  240. procedure About;
  241. var
  242.   D: PDialog;
  243.   Control: PView;
  244.   R: TRect;
  245. begin
  246.   R.Assign(0, 0, 40, 11);
  247.   D := New(PDialog, Init(R, 'About'));
  248.   with D^ do
  249.   begin
  250.     Options := Options or ofCentered;
  251.  
  252.     R.Grow(-1, -1);
  253.     Dec(R.B.Y, 3);
  254.     Insert(New(PStaticText, Init(R,
  255.       #13 +
  256.       ^C'Turbo Vision Demo'#13 +
  257.       #13 +
  258.       ^C'Copyright (c) 1990'#13 +
  259.       #13 +
  260.       ^C'Borland International')));
  261.  
  262.     R.Assign(15, 8, 25, 10);
  263.     Insert(New(PButton, Init(R, 'O~K', cmOk, bfDefault)));
  264.   end;
  265.   if ValidView(D) <> nil then
  266.   begin
  267.     Desktop^.ExecView(D);
  268.     Dispose(D, Done);
  269.   end;
  270. end;
  271.  
  272. procedure AsciiTab;
  273. var
  274.   P: PAsciiChart;
  275. begin
  276.   P := New(PAsciiChart, Init);
  277.   P^.HelpCtx := hcAsciiTable;
  278.   Desktop^.Insert(ValidView(P));
  279. end;
  280.  
  281. procedure OpenStyx;
  282. var
  283.   P: PStyxDemo;
  284. begin
  285.   P := New(PStyxDemo, Init);
  286.   P^.HelpCtx := hcNoContext;
  287.   Desktop^.Insert(ValidView(P));
  288. end;
  289.  
  290. procedure Calculator;
  291. var
  292.   P: PCalculator;
  293. begin
  294.   P := New(PCalculator, Init);
  295.   P^.HelpCtx := hcCalculator;
  296.   if ValidView(P) <> nil then
  297.     Desktop^.Insert(P);
  298. end;
  299.  
  300. procedure Colors;
  301. var
  302.   D: PColorDialog;
  303. begin
  304.   D := New(PColorDialog, Init('',
  305.     ColorGroup('Desktop',
  306.       ColorItem('Color',             32, nil),
  307.     ColorGroup('Menus',
  308.       ColorItem('Normal',            2,
  309.       ColorItem('Disabled',          3,
  310.       ColorItem('Shortcut',          4,
  311.       ColorItem('Selected',          5,
  312.       ColorItem('Selected disabled', 6,
  313.       ColorItem('Shortcut selected', 7, nil)))))),
  314.     ColorGroup('Dialogs/Calc',
  315.       ColorItem('Frame/background',  33,
  316.       ColorItem('Frame icons',       34,
  317.       ColorItem('Scroll bar page',   35,
  318.       ColorItem('Scroll bar icons',  36,
  319.       ColorItem('Static text',       37,
  320.  
  321.       ColorItem('Label normal',      38,
  322.       ColorItem('Label selected',    39,
  323.       ColorItem('Label shortcut',    40,
  324.  
  325.       ColorItem('Button normal',     41,
  326.       ColorItem('Button default',    42,
  327.       ColorItem('Button selected',   43,
  328.       ColorItem('Button disabled',   44,
  329.       ColorItem('Button shortcut',   45,
  330.       ColorItem('Button shadow',     46,
  331.  
  332.       ColorItem('Cluster normal',    47,
  333.       ColorItem('Cluster selected',  48,
  334.       ColorItem('Cluster shortcut',  49,
  335.  
  336.       ColorItem('Input normal',      50,
  337.       ColorItem('Input selected',    51,
  338.       ColorItem('Input arrow',       52,
  339.  
  340.       ColorItem('History button',    53,
  341.       ColorItem('History sides',     54,
  342.       ColorItem('History bar page',  55,
  343.       ColorItem('History bar icons', 56,
  344.  
  345.       ColorItem('List normal',       57,
  346.       ColorItem('List focused',      58,
  347.       ColorItem('List selected',     59,
  348.       ColorItem('List divider',      60,
  349.  
  350.       ColorItem('Information pane',  61, nil))))))))))))))))))))))))))))),
  351.     ColorGroup('Viewer',
  352.       ColorItem('Frame passive',      8,
  353.       ColorItem('Frame active',       9,
  354.       ColorItem('Frame icons',       10,
  355.       ColorItem('Scroll bar page',   11,
  356.       ColorItem('Scroll bar icons',  12,
  357.       ColorItem('Text',              13, nil)))))),
  358.     ColorGroup('Puzzle',
  359.       ColorItem('Frame passive',      8,
  360.       ColorItem('Frame active',       9,
  361.       ColorItem('Frame icons',       10,
  362.       ColorItem('Scroll bar page',   11,
  363.       ColorItem('Scroll bar icons',  12,
  364.       ColorItem('Normal text',       13,
  365.       ColorItem('Highlighted text',  14, nil))))))),
  366.     ColorGroup('Calendar',
  367.       ColorItem('Frame passive',     16,
  368.       ColorItem('Frame active',      17,
  369.       ColorItem('Frame icons',       18,
  370.       ColorItem('Scroll bar page',   19,
  371.       ColorItem('Scroll bar icons',  20,
  372.       ColorItem('Normal text',       21,
  373.       ColorItem('Current day',       22, nil))))))),
  374.     ColorGroup('Ascii table',
  375.       ColorItem('Frame passive',     24,
  376.       ColorItem('Frame active',      25,
  377.       ColorItem('Frame icons',       26,
  378.       ColorItem('Scroll bar page',   27,
  379.       ColorItem('Scroll bar icons',  28,
  380.       ColorItem('Text',              29, nil)))))), nil)))))))));
  381.  
  382.   D^.HelpCtx := hcOCColorsDBox;
  383.   if ValidView(D) <> nil then
  384.   begin
  385.     D^.SetData(Application^.GetPalette^);
  386.     if Desktop^.ExecView(D) <> cmCancel then
  387.     begin
  388.       Application^.GetPalette^ := D^.Pal;
  389.       DoneMemory;  { Dispose all group buffers }
  390.       ReDraw;      { Redraw application with new palette }
  391.     end;
  392.     Dispose(D, Done);
  393.   end;
  394. end;
  395.  
  396. procedure Mouse;
  397. var
  398.   D: PDialog;
  399. begin
  400.   D := New(PMouseDialog, Init);
  401.   D^.HelpCtx := hcOMMouseDBox;
  402.   if ValidView(D) <> nil then
  403.   begin
  404.     D^.SetData(MouseReverse);
  405.     if Desktop^.ExecView(D) <> cmCancel then
  406.       D^.GetData(MouseReverse);
  407.   end;
  408. end;
  409.  
  410. procedure DosShell;
  411. begin
  412.   DoneSysError;
  413.   DoneEvents;
  414.   DoneVideo;
  415.   DoneMemory;
  416.   SetMemTop(HeapPtr);
  417.   PrintStr('Type EXIT to return...');
  418.   SwapVectors;
  419.   Exec(GetEnv('COMSPEC'), '');
  420.   SwapVectors;
  421.   SetMemTop(HeapEnd);
  422.   InitMemory;
  423.   InitVideo;
  424.   InitEvents;
  425.   InitSysError;
  426.   Redraw;
  427. end;
  428.  
  429. procedure RetrieveDesktop;
  430. var
  431.   S: PStream;
  432. begin
  433.   S := New(PBufStream, Init('TVDEMO.DSK', stOpenRead, 1024));
  434.   if LowMemory then OutOfMemory
  435.   else if S^.Status <> stOk then
  436.     MessageBox('Could not open desktop file', nil, mfOkButton + mfError)
  437.   else
  438.   begin
  439.     LoadDesktop(S^);
  440.     if S^.Status <> stOk then
  441.       MessageBox('Error reading desktop file', nil, mfOkButton + mfError);
  442.   end;
  443.   Dispose(S, Done);
  444. end;
  445.  
  446. procedure SaveDesktop;
  447. var
  448.   S: PStream;
  449.   F: File;
  450. begin
  451.   S := New(PBufStream, Init('TVDEMO.DSK', stCreate, 1024));
  452.   if not LowMemory and (S^.Status = stOk) then
  453.   begin
  454.     StoreDesktop(S^);
  455.     if S^.Status <> stOk then
  456.     begin
  457.       MessageBox('Could not create TVDEMO.DSK.', nil, mfOkButton + mfError);
  458.       {$I-}
  459.       Dispose(S, Done);
  460.       Assign(F, 'TVDEMO.DSK');
  461.       Erase(F);
  462.       Exit;
  463.     end;
  464.   end;
  465.   Dispose(S, Done);
  466. end;
  467.  
  468.  
  469. begin
  470.   TApplication.HandleEvent(Event);
  471.   case Event.What of
  472.     evCommand:
  473.       begin
  474.         case Event.Command of
  475.           cmFOpen: FileOpen('*.*');
  476.           cmChDir: ChangeDir;
  477.           cmCascade: Cascade;
  478.           cmTile: Tile;
  479.           cmAbout: About;
  480.           cmPuzzle: Puzzle;
  481.           cmCalendar: Calendar;
  482.           cmAsciiTab: AsciiTab;
  483.           cmCalculator: Calculator;
  484.           cmColors: Colors;
  485.           cmMouse: Mouse;
  486.           cmDosShell: DosShell;
  487.           cmSaveDesktop: SaveDesktop;
  488.           cmRetrieveDesktop: RetrieveDesktop;
  489.           cmStyx: OpenStyx;
  490.         else
  491.           Exit;
  492.         end;
  493.         ClearEvent(Event);
  494.       end;
  495.   end;
  496. end;
  497.  
  498. procedure TTVDemo.Idle;
  499.  
  500. function IsTileable(P: PView): Boolean; far;
  501. begin
  502.   IsTileable := P^.Options and ofTileable <> 0;
  503. end;
  504.  
  505. procedure DoProdStyx(P: PView); far;
  506. begin
  507.   Message(P, evCommand,cmProdStyx, nil);
  508. end;
  509.  
  510. begin
  511.   TApplication.Idle;
  512. {  Clock^.Update;
  513.   Heap^.Update;}
  514.  
  515.   Desktop^.ForEach(@DoProdStyx);
  516.  
  517.   if Desktop^.FirstThat(@IsTileable) <> nil then
  518.     EnableCommands([cmTile, cmCascade])
  519.   else
  520.     DisableCommands([cmTile, cmCascade]);
  521. end;
  522.  
  523. procedure TTVDemo.InitMenuBar;
  524. var
  525.   R: TRect;
  526. begin
  527.   GetExtent(R);
  528.   R.B.Y := R.A.Y+1;
  529.   MenuBar := New(PMenuBar, Init(R, NewMenu(
  530.     NewSubMenu('~'#240'~', hcSystem, NewMenu(
  531.       NewItem('~A~bout', '', kbNoKey, cmAbout, hcSAbout,
  532.       NewLine(
  533.       NewItem('~P~uzzle', '', kbNoKey, cmPuzzle, hcSPuzzle,
  534.       NewItem('Ca~l~endar', '', kbNoKey, cmCalendar, hcSCalendar,
  535.       NewItem('Ascii ~t~able', '', kbNoKey, cmAsciiTab, hcSAsciiTable,
  536.       NewItem('~S~tyx', '', kbNoKey, cmStyx, hcNoContext,
  537.       NewItem('~C~alculator', '', kbNoKey, cmCalculator, hcCalculator, nil)))))))),
  538.     NewSubMenu('~F~ile', hcFile, NewMenu(
  539.       NewItem('~O~pen...', 'F3', kbF3, cmFOpen, hcFOpen,
  540.       NewItem('~C~hange dir...', '', kbNoKey, cmChDir, hcFChangeDir,
  541.       NewLine(
  542.       NewItem('~D~OS shell', '', kbNoKey, cmDosShell, hcFDosShell,
  543.       NewItem('E~x~it', 'Alt-X', kbAltX, cmQuit, hcFExit, nil)))))),
  544.     NewSubMenu('~W~indows', hcWindows, NewMenu(
  545.       NewItem('~R~esize/move','Ctrl-F5', kbCtrlF5, cmResize, hcWSizeMove,
  546.       NewItem('~Z~oom', 'F5', kbF5, cmZoom, hcWZoom,
  547.       NewItem('~N~ext', 'F6', kbF6, cmNext, hcWNext,
  548.       NewItem('~C~lose', 'Alt-F3', kbAltF3, cmClose, hcWClose,
  549.       NewItem('~T~ile', '', kbNoKey, cmTile, hcWTile,
  550.       NewItem('C~a~scade', '', kbNoKey, cmCascade, hcWCascade, nil))))))),
  551.     NewSubMenu('~O~ptions', hcOptions, NewMenu(
  552.       NewItem('~M~ouse...', '', kbNoKey, cmMouse, hcOMouse,
  553.       NewItem('~C~olors...', '', kbNoKey, cmColors, hcOColors,
  554.       NewLine(
  555.       NewItem('~S~ave desktop', '', kbNoKey, cmSaveDesktop, hcOSaveDesktop,
  556.       NewItem('~R~etrieve desktop', '', kbNoKey, cmRetrieveDesktop, hcORestoreDesktop, nil)))))), nil)))))));
  557. end;
  558.  
  559. procedure TTVDemo.InitStatusLine;
  560. var
  561.   R: TRect;
  562. begin
  563.   GetExtent(R);
  564.   R.A.Y := R.B.Y - 1;
  565.   StatusLine := New(PStatusLine, Init(R,
  566.     NewStatusDef(0, $FFFF,
  567.       NewStatusKey('~F1~ Help', kbF1, cmHelp,
  568.       NewStatusKey('~F3~ Open', kbF3, cmFOpen,
  569.       NewStatusKey('~Alt-F3~ Close', kbAltF3, cmClose,
  570.       NewStatusKey('~F5~ Zoom', kbF5, cmZoom,
  571.       NewStatusKey('', kbF10, cmMenu,
  572.       NewStatusKey('', kbCtrlF5, cmResize, nil)))))), nil)));
  573. end;
  574.  
  575. procedure TTVDemo.OutOfMemory;
  576. begin
  577.   MessageBox('Not enough memory available to complete operation.',
  578.     nil, mfError + mfOkButton);
  579. end;
  580.  
  581. { Since the safety pool is only large enough to guarantee that allocating
  582.   a window will not run out of memory, loading the entire desktop without
  583.   checking LowMemory could cause a heap error.  This means that each
  584.   window should be read individually, instead of using Desktop's Load.
  585. }
  586.  
  587. procedure TTVDemo.LoadDesktop(var S: TStream);
  588. var
  589.   P: PView;
  590.  
  591. procedure CloseView(P: PView); far;
  592. begin
  593.   Message(P, evCommand, cmClose, nil);
  594. end;
  595.  
  596. begin
  597.   if Desktop^.Valid(cmClose) then
  598.   begin
  599.     Desktop^.ForEach(@CloseView); { Clear the desktop }
  600.     repeat
  601.       P := PView(S.Get);
  602.       Desktop^.InsertBefore(ValidView(P), Desktop^.Last);
  603.     until P = nil;
  604.   end;
  605. end;
  606.  
  607. procedure TTVDemo.StoreDesktop(var S: TStream);
  608.  
  609. procedure WriteView(P: PView); far;
  610. begin
  611.   if P <> Desktop^.Last then S.Put(P);
  612. end;
  613.  
  614. begin
  615.   Desktop^.ForEach(@WriteView);
  616.   S.Put(nil);
  617. end;
  618.  
  619. procedure TTVDemo.ViewFile(FileName: PathStr);
  620. var
  621.   W: PWindow;
  622. begin
  623.   W := New(PFileWindow,Init(FileName));
  624.   W^.HelpCtx := hcViewer;
  625.   if ValidView(W) <> nil then
  626.     Desktop^.Insert(W);
  627. end;
  628.  
  629. var
  630.   Demo: TTVDemo;
  631.  
  632. begin
  633.   Demo.Init;
  634.   Demo.Run;
  635.   Demo.Done;
  636. end.
  637.